//
// Created by shine on 2019/11/10.
//
#include "yuvReader.h"
#include "MakeFileDir.h"

int main(int argc, char *argv[]){

    yuvReader Reader(argv[1], argv[2],argv[3]);
//    Reader.Play();
    Reader.addNoise();
//    Reader.Cut("VideoProCut/new/G10PandaBaseChengdu_3840x1920.yuv", 0, 30);
    return 0;
}

yuvReader::yuvReader(const string& filePath, const string& width, const string& height) {

    _filePath = filePath;
    _videoName = _filePath.substr(_filePath.find_last_of('/') + 1, _filePath.find_last_of('.') - _filePath.find_last_of('/') - 1);
    _videoWidth = atoi(width.c_str());
    _videoHeight = atoi(height.c_str());
    _framePixelNums = _videoHeight * _videoWidth * 3 / 2;

    cout<< "rgb视频像素:"<< _videoWidth << "*" << _videoHeight << " = " << _videoWidth * _videoHeight << endl;
    cout<< "yuv视频像素:"<< _framePixelNums << endl;

    _fin.open(filePath, ios_base::in|ios_base::binary);
    if(_fin.fail())
    {
        cout << "the file is error" << endl;
    }

    _fin.seekg(0, ios::end);   //设置文件指针到文件流的尾部
    streampos ps = _fin.tellg();  //指出当前的文件指针
    unsigned long NumberPixel = ps;
    cout << "Number of pixel: " << ps << endl;  //输出指针的位置
    _FrameCount = ps / _framePixelNums; //帧大小
    cout << "frameNumber: " << _FrameCount << endl; //输出帧数
    _fin.close();

    createDirectory("VideoFrame/" + _videoName + "/");
}

void yuvReader::Play() {

    _fileIn = fopen(_filePath.c_str(), "rb+");
    unsigned char* _pYuvBuf = new unsigned char[_framePixelNums];//一帧数据大小


    for(int i = 0; i < _FrameCount; ++i) {
        fread(_pYuvBuf, _framePixelNums * sizeof(unsigned char), 1, _fileIn);
        _yuvFrame.create(_videoHeight * 3 / 2, _videoWidth, CV_8UC1);
        memcpy(_yuvFrame.data, _pYuvBuf, _framePixelNums * sizeof(unsigned char));

        cv::cvtColor(_yuvFrame, _rgbFrame, CV_YUV2BGR_I420);
        namedWindow("rgbFrame",CV_WINDOW_NORMAL);
        namedWindow("yuvFrame",CV_WINDOW_NORMAL);
        cv::imshow("yuvFrame", _yuvFrame); //只显示y分量
        cv::imshow("rgbFrame", _rgbFrame);

//        cv::imwrite("VideoFrame/" + _videoName + "/" + _videoName + "_" + to_string(i) + ".jpg", _rgbFrame);

        printf("第 %d 帧\n", i);

        int c = waitKey(30);
        if ((char) c == 27) {
            break;
        }
    }

    fclose(_fileIn);
    while(waitKey() != 27);
    destroyAllWindows();
    delete [] _pYuvBuf;

}

void yuvReader::addNoise() {

    cv::RNG rng1(cvGetTickCount());
    cv::RNG rng2(cvGetTickCount()+cvGetTickCount());
    double w_sigma=1.0;

    _fileIn = fopen(_filePath.c_str(), "rb+");
    string yuvrecFileOutName = "VideoFrame/" + _videoName + "/" + _videoName + "_rec.yuv";
    string rgbsrcFileOutName = "VideoFrame/" + _videoName + "/" + _videoName + "_src.mp4";
    string rgbrecFileOutName = "VideoFrame/" + _videoName + "/" + _videoName + "_rec.mp4";
    string maskFileOutName = "VideoFrame/" + _videoName + "/" + _videoName + "_mask.png";

    FILE* yuvrecFileOut = fopen(yuvrecFileOutName.c_str(), "w+");
    VideoWriter rgbsrcVideo(rgbsrcFileOutName, CV_FOURCC('m', 'p', '4', 'v'), 2.0, Size(_videoWidth, _videoHeight));
    VideoWriter rgbrecVideo(rgbrecFileOutName, CV_FOURCC('m', 'p', '4', 'v'), 2.0, Size(_videoWidth, _videoHeight));

    unsigned char* _pYuvBuf = new unsigned char[_framePixelNums];//一帧数据大小

    ///高斯模糊区域
    int startx = rng1(1840);
    int starty = rng2(1020);
    cout << "startx:"<< startx << endl;
    cout << "starty:"<< starty << endl;
    Mat mask = Mat::zeros(Size(_videoWidth,_videoHeight), CV_8UC1);
    cv::Mat maskRoi1(mask,cv::Rect(startx, starty, 2000, 900));
    maskRoi1 = 255;
    namedWindow("mask",CV_WINDOW_NORMAL);
    cv::imshow("mask",mask);
    imwrite(maskFileOutName,mask);

    for(int i = 0; i < _FrameCount; ++i) {
        fread(_pYuvBuf, _framePixelNums * sizeof(unsigned char), 1, _fileIn);
        _yuvFrame.create(_videoHeight * 3 / 2, _videoWidth, CV_8UC1);
        memcpy(_yuvFrame.data, _pYuvBuf, _framePixelNums * sizeof(unsigned char));

        namedWindow("yuvFrame",CV_WINDOW_NORMAL);
        cv::imshow("yuvFrame", _yuvFrame); //只显示y分量

        //yuv转为rgb
        cv::cvtColor(_yuvFrame, _rgbFrame, CV_YUV2BGR_I420);
        namedWindow("rgbFrame",CV_WINDOW_NORMAL);
        cv::imshow("rgbFrame", _rgbFrame);
        rgbsrcVideo << _rgbFrame;


        ///对rgb添加高斯模糊
        cv::Mat blurRoi(_rgbFrame,cv::Rect(startx, starty, 2000, 900));
        GaussianBlur(blurRoi, blurRoi, Size(9, 9), 5);
        
        namedWindow("bluredRgbFrame",CV_WINDOW_NORMAL);
        cv::imshow("bluredRgbFrame", _rgbFrame);

        //rgb转回yuv
        Mat _bluredYuvFrame;
        cv::cvtColor(_rgbFrame,_bluredYuvFrame , CV_BGR2YUV_I420);
        namedWindow("bluredYuvFrame",CV_WINDOW_NORMAL);
        cv::imshow("bluredYuvFrame", _bluredYuvFrame); //只显示y分量

//        cv::imwrite("VideoFrame/" + _videoName + "/" + _videoName + "_" + to_string(i) + ".jpg", _rgbFrame);
        fwrite(_bluredYuvFrame.data, _framePixelNums*sizeof(unsigned char), 1, yuvrecFileOut);
        rgbrecVideo << _rgbFrame;

        printf("第 %d 帧\n", i);

        int c = waitKey(30);
        if ((char) c == 27) {
            break;
        }
    }

    fclose(_fileIn);
    fclose(yuvrecFileOut);
//    while(waitKey() != 27);
    destroyAllWindows();

}

void yuvReader::Cut(const string& outputYUV, int offsetNum, int frameNum) {


    if (nullptr == (_FileOut = fopen(outputYUV.c_str(), "wb"))){
        printf("File output is can't open!\n");
        fclose(_FileOut);
    }

    if (nullptr == (_fileIn = fopen(_filePath.c_str(), "rb+"))){
        printf("File input is can't open!\n");
        fclose(_fileIn);
    }

    unsigned char* _pCutBuf = new unsigned char[_framePixelNums * frameNum];//一帧数据大小
    unsigned char* _pOffsetBuf = new unsigned char[_framePixelNums * offsetNum];//一帧数据大小

    fread(_pOffsetBuf, _framePixelNums * sizeof(unsigned char), offsetNum, _fileIn);
    delete _pOffsetBuf;

    fread(_pCutBuf, _framePixelNums * sizeof(unsigned char), frameNum, _fileIn);
    fwrite(_pCutBuf, _framePixelNums * sizeof(unsigned char), frameNum, _FileOut);
    delete _pCutBuf;

    fclose(_fileIn);
    fclose(_FileOut);

    cout << "Video Cut Finished..." << endl;
}

